<?php

/**
* Image Proprertys
*@author Rafael Freitas Lima rafaellive@gmail.com
*/
class ImageProperty
{
	public $name;
	public $fullname;
	public $urlname;
	public $width;
	public $height;
	public $mime;
	public $type;
	public $size;
	public $path;
	public $extension;
	public $attributes;
	public $bits;
	public $channels;
}

class WaterMarkPosition {
	
	const Center = 0;
	const CenterLeft = 8;
	const CenterRight = 6;
	const TopCenter = 5;
	const TopLeft = 1;
	const TopRight = 2;
	const BottomCenter = 7;
	const BottomRight = 3;
	const BottomLeft = 4;
}

/**
*Class to build images
*@author Rafael Freitas Lima rafaellive@gmail.com
*/
class ImageUtil
{
	/**
	 * Caminho do Arquivo fonte
	 *
	 * @var string
	 */
	protected $_file;
	/**
	 * Informações da imagens
	 *
	 * @var array
	 */
	protected $_arrFileInfo;
	/**
	*@var ImageFilenameProcessor
	*/
	protected $_processorFile;
	/**
	*@var ImageFilenameProcessor
	*/
	protected $_processorNewFile;
	/**
	*@var int
	*/
	protected $_width = null;
	/**
	*@var int
	*/
	protected $_height = null;
	protected $_cutX = 0;
	protected $_cutY = 0;
	protected $_cutWidth = 0;
	protected $_cutHeight = 0;
	/**
	*@var ImageProperty
	*/
	protected $_property;
	/**
	*@var Resource
	*/
	protected $_resource;
	/**
	 * Cut image?
	 *
	 * @var bool
	 */
	protected $_cutImage;
	
	/**
	 * Generate new images from a image source
	 *
	 * @param string $filename
	 * @param ImageFilenameProcessor $newfilename
	 */
	public function ImageUtil($filename, $newfilename = null)
	{
		$this->_file = $filename;
		$this->_property = new ImageProperty();
		$this->_processorNewFile = $newfilename;
		$this->_cutImage = false;
		$this->Verify();
	}
	
	/**
	 * Cut image?
	 *
	 * @param bool $value
	 */
	public function enableCutImage($value)
	{
		$this->_cutImage = $value;
	}
	
	/**
	 * Set new file name
	 *
	 * @param ImageFilenameProcessor $file
	 */
	public function setNewFileName($file)
	{
		$this->_processorNewFile = $file;
	}
	
	/**
	*@param int $width
	*@param int $height
	*@return void
	*/
	public function setDimension($width, $height)
	{
		if ($width > 0 && !is_null($width)) 
		{
			$this->_width = $width;
		}
		if ($height > 0 && !is_null($height)) 
		{
			$this->_height = $height;
		}
	}	
	/**
	*@desc Verify suported file image
	*@throws Exception
	*@return bool
	*/
	public function Verify()
	{
		if (!file_exists($this->_file)) 
		{
			throw new Exception("Image not found! Path: $this->_file");
		}
		
		$path = pathinfo($this->_file);
		$this->_arrFileInfo = $path;
		
		$imageInfo = getimagesize($this->_file);
		$this->_property->mime = $imageInfo['mime'];
		$this->_property->type = $imageInfo[2];
		$this->_property->attributes = $imageInfo[3];
		$this->_property->width = $imageInfo[0];
		$this->_property->height = $imageInfo[1];
		$this->_property->size = filesize($this->_file);
		$this->_property->extension = $path['extension'];
		$this->_property->name = $this->_file;
		$this->_property->bits = $imageInfo['bits'];
		$this->_property->channels = $imageInfo['channels'];
		$this->_property->fullname = $this->_file;
		$this->_property->urlname = str_replace('\\', '/', $this->_file);
		$this->_cutWidth = $this->_property->width;
		$this->_cutHeight = $this->_property->height;
		
		$no_suport = true;
		$suported = array();
		$suported[] = IMAGETYPE_JPEG;
		$suported[] = IMAGETYPE_GIF;
		$suported[] = IMAGETYPE_PNG;
//		$suported[] = IMAGETYPE_BMP;
		foreach ($suported as $type) 
		{
			if( $this->_property->type == $type)
			{
				$no_suport = false;
			}
		}
		if ($no_suport) 
		{
			throw new Exception("Type no suported!");
		}
		return $no_suport;
	}

	/**
	 * Get image properties
	 *
	 * @return ImageProperty
	 */
	public function getImageProperties()
	{
		return $this->_property;
	}
	
	/**
	 * Calculate ratio image dimension
	 *
	 */
	protected function ratioImageDimension()
	{
		$average = 1;
		if($this->_property->height > $this->_width || $this->_property->width > $this->_height)
		{
			$object_ratio = $this->_height / $this->_width;
			$image_ratio = $this->_property->width / $this->_property->height;
			if($image_ratio < $object_ratio)
			{
				$average = $this->_width / $this->_property->height;
			}
			else 
			{
				$average = $this->_height / $this->_property->width;
			}
			
			$this->_width = $this->_property->width * $average;
			$this->_height = $this->_property->height * $average;
		}
		else 
		{
			$this->_width = $this->_property->width;
			$this->_height = $this->_property->height;
		}
	}
	
	public function cutImage($x, $y, $width, $height)
	{
		$this->_cutX = $x;
		$this->_cutY = $y;
		$this->_cutWidth = $width;
		$this->_cutHeight = $height;
	}
	/**
	*@desc Create new image from image source
	*@return ImageProperty
	*/
	public function generateImage($ratio = true)
	{
//		$memoryNeeded = round(($this->_property->width * $this->_property->height * $this->_property->bits * $this->_property->channels / 8 + Pow(2, 16)) * 1.65);
//	    ini_set("memory_limit", (Memory_Get_Usage() + $memoryNeeded));

		if (!$this->_width || !$this->_height)
		{
			$this->_width = $this->_property->width;
			$this->_height = $this->_property->height;
		}
		
	    switch( $this->_property->type )
	    { 
		    case IMAGETYPE_PNG : $this->_resource = imagecreatefrompng($this->_property->fullname); break;
		    case IMAGETYPE_JPEG : $this->_resource = imagecreatefromjpeg($this->_property->fullname); break;
		    case IMAGETYPE_GIF : $this->_resource = imagecreatefromgif($this->_property->fullname); break;
//		    case IMAGETYPE_BMP : $this->_resource = imagecreatefromwbmp($this->_property->fullname); break;
		    default: break;
	    }
		if (!$this->_resource) 
		{
			throw new ImageUtilExecption(802, "Image fails when creating from source.");
		}
		
		if ($ratio) 
		{
			$this->ratioImageDimension();
		}
		
		if (get_class($this->_processorNewFile) == 'ImageFilenameProcessor') 
		{
			if ($this->_processorNewFile->Extension() == '.*') 
			{
				$this->_processorNewFile->setExtension($this->_arrFileInfo['extension']);
			}
			if (strpos($this->_processorNewFile->ToString(), '*') !== false) 
			{
				$newName = str_replace('*', $this->_file, $this->_processorNewFile->ToString());
				$this->_processorNewFile->setName($newName);
			}
			$stringSaveImageTo = $this->_processorNewFile->FullQualifiedNameAndPath();
		}
		else 
		{
			$stringSaveImageTo = $this->_property->fullname;
		}
		
		FileUtil::ForceDirectories(dirname($stringSaveImageTo));
		
		$newImageResource = imagecreatetruecolor($this->_width, $this->_height);
		//recorta imagem?
		if ($this->_cutImage)
		{
			$boolImageCopied = imagecopyresampled($newImageResource, 
											$this->_resource, 0, 0, 
											$this->_cutX, $this->_cutY, 
											$this->_width, $this->_height, 
											$this->_cutWidth, $this->_cutHeight);
		}
		else
		{
			$boolImageCopied = imagecopyresampled($newImageResource, 
											$this->_resource, 0, 0, 
											0, 0, 
											$this->_width, $this->_height, 
											$this->_property->width, $this->_property->height);
		}
		
		if (!$boolImageCopied) 
		{
			throw new ImageUtilExecption(806, "Can't to copy image file.");
		}
		
		switch( strtolower($this->_processorNewFile->Extension()) )
	    { 
		    case '.png' : imagepng($newImageResource, $stringSaveImageTo); break;
		    case '.jpg' : imagejpeg($newImageResource, $stringSaveImageTo, 100); break;
		    case '.gif' : imagegif($newImageResource, $stringSaveImageTo); break;
		    default: imagejpeg($newImageResource, $stringSaveImageTo, 100); break;
	    }
		imagedestroy($newImageResource);
		
		$newImageInfo = getimagesize($stringSaveImageTo);
		$newImageProperty = new ImageProperty();
		$newImageProperty->mime = $newImageInfo['mime'];
		$newImageProperty->type = $newImageInfo[2];
		$newImageProperty->attributes = $newImageInfo[3];
		$newImageProperty->width = $newImageInfo[0];
		$newImageProperty->height = $newImageInfo[1];
		$newImageProperty->size = filesize($stringSaveImageTo);
		$newImageProperty->extension = $this->_processorNewFile->Extension();
		$newImageProperty->name = $this->_processorNewFile->ToString();
		$newImageProperty->bits = $newImageInfo['bits'];
		$newImageProperty->channels = $newImageInfo['channels'];
		$newImageProperty->fullname = $stringSaveImageTo;
		$newImageProperty->urlname = str_replace(FileUtil::Slash(), '/', $this->_processorNewFile->FullQualifiedNameAndPath());
		$newImageProperty->path = $this->_processorNewFile->FullQualifiedNameAndPath();
		return $newImageProperty;
	}
	

    /**
    * Puts a WaterMark in the image and you can choice the position
    *
    * The positions is:
    *
    * Nos parâmetros de imagem fonte, marca dagua e imagem destino, você pode
    * usar ou imagens PNG ou JPEG ou ambos os tipos, exemplos:
    * WaterMark("foto.png", "agua.jpg", "foto.png", 1, 50);
    * WaterMark("foto.jpg", "agua.jpg", "foto.jpg", 1, 50);
    * WaterMark("foto.jpg", "agua.png", "foto.jpg", 1, 50);
    * WaterMark("foto.jpg", "agua.png", "foto.png", 1, 50);
    * WaterMark("foto.png", "agua.png", "foto.png", 1, 50);
    *
    * @param string $image O caminho da imagem em que a marca da água será adicionada, ex: "imagens/foto.jpg"
    * @param string $watermark O caminho da imagem marca d'água, ex: "imagens/marca.jpg"
    * @param string $newimage O nome da nova imagem, ex: "imagens/nova.png"
    * @param integer $pos A posição da marca da água (veja acima)
    * @param integer $transicao (0 a 100) Transparência da Marca d'Água - Menor número > Transparência
    */
    
    /**
     * Enter description here...
     *
     * @param string $image
     * @param string $watermark
     * @param string $newimage
     * @param WaterMarkPosition $position
     * @param integer $transparency
     */
	public function WaterMark($image, $watermark, $newimage, $position = WaterMarkPosition::BottomRight, $transparency = 100)
    {
    	$img = $this->_property;
    	switch ($img->extension)
    	{
    		case '.jpg':
    			$watermark_id = imagecreatefromjpeg($watermark);
    			$image_id = imagecreatefromjpeg($image);
    			break;
    		case '.png':
    			$watermark_id = imagecreatefrompng($watermark);
    			$image_id = imagecreatefrompng($image);
    			break;
    		default: throw new ImageUtilExecption(801, "Type no suported!");
    	}
    	
		$image_width		= $img->width;
		$image_height		= $img->height;
		
		$watermark_data		= getimagesize($watermark); 
		$watermark_width	= $watermark_data[0];
		$watermark_height	= $watermark_data[1];
		
		switch ($position) {
			//centralizado
			case 0:
				$dest_x = ($image_width / 2) - ($watermark_width / 2);
				$dest_y = ($image_height / 2) - ($watermark_height / 2);
				break;
			//topo esquerdo
			case 1:
				$dest_x = 0;
				$dest_y = 0;
				break;
			//topo direito
			case 2:
				$dest_x = $image_width - $watermark_width;
				$dest_y = 0;
				break;
			//rodapé direito
			case 3:
				$dest_x = ($image_width - $watermark_width) - 5;
				$dest_y = ($image_height - $watermark_height) - 5;
				break;
			//rodaé esquerdo
			case 4:
				$dest_x = 0;
				$dest_y = $image_height - $watermark_height;
				break;
			//topo centralizado
			case 5:
				$dest_x = ( ( $image_width - $watermark_width ) / 2 );
				$dest_y = 0;
				break;
			//centro direito
			case 6:
				$dest_x = $image_width - $watermark_width; 
				$dest_y = ( $image_height / 2 ) - ( $watermark_height / 2 );
				break;
			//rodapé centralizado
			case 7:
				$dest_x = ( ( $image_width - $watermark_width ) / 2 );
				$dest_y = $image_height - $watermark_height;
				break;
			//centro esquerdo
			case 8:
				$dest_x = 0;
				$dest_y = ( $image_height / 2 ) - ( $watermark_height / 2 );
				break;
			//rodape direito como default
			default:
				$dest_x = ($image_width - $watermark_width) - 5;
				$dest_y = ($image_height - $watermark_height) - 5;
				break;
		}

		imagecopymerge($image_id, $watermark_id, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height, $transparency);

		if ($img->extension == '.jpg')
		{
			imagejpeg($image_id, $newimage, 70);
		}
		else
		{
			imagepng($image_id, $newimage, 70);
		}
    }
    
    /**
     * Gerar miniatura de uma imagem. Ex: nomeArquivo.thumb.jpg
     *
     * @param string $filename
     * @param int $width
     * @param int $height
     * @param bool $ratio
     * @return ImageProperty
     */
    public static function Thumbnail($filename, $width, $height, $ratio = true)
    {
    	$path = pathinfo($filename);
    	$path['filename'] = basename($path['basename'], '.' . $path['extension']);
    	
    	$name = $path['dirname'] . '/' . $path['filename'] . '.thumb';
    	
    	if ($path['extension'])
    	{
    		$name .= '.' . $path['extension'];
    	}
    	
		$fileThumb = new ImageFilenameProcessor($name);
		$img = new ImageUtil($filename, $fileThumb);
		$img->setDimension(70, 85);
		$pro = $img->generateImage($ratio);
		return $pro;
    }
}